package next_flag_search;

import env.Action;
import env.Enviroment;
import env.Orientation;
import env.TileType;
import java.util.LinkedList;
import java.util.List;

/*************************************************************
 * ************************************************************
 * NOTE: FOR NOW, g=depth always!!!
 * @author user
 *************************************************************
 *************************************************************/
public class Node {

    public static Enviroment env;
    private Node parent;
    private int depth;
    private int g; //path cost FOR NOW, g=depth always!!!
    private Action action; //what got me here?
    // State:
    private int row,  col;
    private Orientation orientation;

    public Node(Node parent, Action action, int depth, int g, int row, int col, Orientation orientation) {
        this.parent = parent;
        this.action = action;
        this.depth = depth;
        this.g = g;
        this.row = row;
        this.col = col;
        this.orientation = orientation;

    }

    public LinkedList<Action> getActionPath() {
        LinkedList<Action> ans = new LinkedList<Action>();
        for (Node i = this; i.parent != null; i = i.parent) {
            ans.addFirst(i.action);
        }
        return ans;
    }

    public int getCol() {
        return col;
    }

    public int getRow() {
        return row;
    }

    public int getDepth() {
        return depth;
    }

    public int getG() {
        return g;
    }
    
    //returns 2 or 3 nodes( left, right, and maybe forward )
    public List<Node> expand() {
        List<Node> ans = new LinkedList<Node>();
        
        //can't turn on ice!
        if (!Enviroment.env.map[row][col].isIce()) {
            ans.add(new Node(this, action.left, depth + 1, g + 1, row, col, Orientation.turn(orientation, Action.left))); //L
            ans.add(new Node(this, action.right, depth + 1, g + 1, row, col, Orientation.turn(orientation, Action.right))); //R
        }
        //check if forward is possible:
        switch (orientation) {
            case North: {
                row--;
                break;
            }
            case East: {
                col++;
                break;
            }
            case West: {
                col--;
                break;
            }
            case South: {
                row++;
                break;
            }
        }
        //TODO: this was a nasty bug: i was treating env as a constant, while MY AGENT would be moving!
        //if (Enviroment.env.isCellFree(fwd.getRow(), fwd.getCol())) {
        if (!Enviroment.env.map[row][col].isWall()) {
            ans.add(new Node(this, action.fwd, depth + 1, g + 1, row, col, orientation)); //F
        }
        return ans;
    }

    public boolean equals(Node e) {
        return row == e.row && col == e.col && orientation == e.orientation;
    }

    @Override
    public int hashCode() {
        return row * col * orientation.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Node other = (Node) obj;
        if (this.row != other.row) {
            return false;
        }
        if (this.col != other.col) {
            return false;
        }
        if (this.orientation != other.orientation) {
            return false;
        }
        return true;
    }
}
